<template>
  <div class="bee-ele-colorPicker">
    <div class="bee-ele-row">
      <saturation
        class="bee-ele-saturation"
        :hidden="true"
        :saturation="currentColor.hsv.s"
        :hue="currentColor.hsv.h"
        :value="currentColor.hsv.v"
        @change="onSaturationChange"
      />
      <hue
        class="bee-ele-hue"
        :vertical="true"
        size="small"
        :hue="currentColor.hsv.h"
        @change="onHueChange"
        v-if="!disableHue"
      />
    </div>
    <alpha
      style="width: 257px"
      :color="currentColor.hex8"
      @change="onAlphaChange"
      :alpha="currentColor.alpha"
      v-if="!disableAlpha"
    />

    <v-color-input v-if="!disableColorInput" style="width: 257px" :color="currentColor" @change="onInputChange" />

    <history
      :color-list="storageColorList"
      :round="historyRound"
      @change="onCompactChange"
      v-if="!disableHistory"
    />
  </div>
</template>

<script lang="ts" setup name="EleColorPicker">
import { onMounted, PropType, ref, toRaw, watch } from 'vue'
import Saturation from './common/Saturation.vue'
import Hue from './common/Hue.vue'
import Alpha from './common/Alpha.vue'
import History from './common/History.vue'
import VColorInput from './common/VColorInput.vue'
import {
  Color,
  ColorAttrs,
  ColorFormat,
  ColorInput,
  debounceFn,
  MAX_STORAGE_LENGTH,
  STORAGE_COLOR_KEY
} from './color'
import ls from '@/utils/Storage'

const props = defineProps({
  color: {
    type: [String, Object] as PropType<ColorInput>,
    default: '#000000'
  },
  format: {
    type: String as PropType<ColorFormat>
  },
  disableAlpha: Boolean,
  disableHue: Boolean,
  disableHistory: Boolean,
  disableColorInput: Boolean,
  historyRound: {
    type: Boolean,
    default: true
  }
})

const emit = defineEmits(['update:color', 'change'])
const colorClass = new Color()

const currentColor = ref<ColorAttrs>(colorClass.parseColor(props.color))

const storageColorList = ref<string[]>([])

const onStorageColor = () => {
  storageColorList.value = storageColorList.value.filter((value) => {
    return value !== currentColor.value.hex8
  })
  if (storageColorList.value.length >= MAX_STORAGE_LENGTH) {
    storageColorList.value.shift()
  }
  storageColorList.value.push(currentColor.value.hex8)
  ls.set(STORAGE_COLOR_KEY, storageColorList.value)
}

const onInitColorList = () => {
  storageColorList.value = ls.get(STORAGE_COLOR_KEY) || []
}

const doOnChange = (data: any, oldHue?: number): void => {
  currentColor.value = colorClass.parseColor(data, oldHue)
  debounceFn(onStorageColor)
}

const doUpdate = () => {
  if (props.format) {
    emit('update:color', colorClass.format(props.format))
    emit('change', colorClass.format(props.format))
  } else {
    emit('update:color', currentColor.value)
    emit('change', currentColor.value)
  }
}

const onCompactChange = (color: string) => {
  doOnChange(color)
  doUpdate()
}

const onAlphaChange = (alpha: number) => {
  doOnChange(
    {
      h: currentColor.value.hsl.h,
      s: currentColor.value.hsl.s,
      l: currentColor.value.hsl.l,
      a: alpha,
      source: 'alpha'
    },
    currentColor.value.hsl.h
  )
  doUpdate()
}

const onSaturationChange = (saturation: number, bright: number) => {
  doOnChange(
    {
      h: currentColor.value.hsv.h,
      s: saturation,
      v: bright,
      a: currentColor.value.hsv.a,
      source: 'saturation'
    },
    currentColor.value.hsv.h
  )
  doUpdate()
}

const onHueChange = (hue: number) => {
  const { s: saturation, v: bright, a: alpha } = currentColor.value.hsv
  doOnChange(
    {
      h: hue,
      s: saturation,
      v: bright,
      a: alpha,
      source: 'hue'
    },
    hue
  )

  doUpdate()
}

const onInputChange = (val: ColorAttrs) => {
  currentColor.value = val
  doUpdate()
}

watch(
  () => props.color,
  (newVal: ColorInput) => {
    doOnChange(toRaw(newVal))
    onInitColorList()
  }
)

onMounted(() => {
  onInitColorList()
})
</script>

<style lang="less" scoped>
.bee-ele-colorPicker {
  position: relative;
  box-sizing: border-box;
  border-radius: 3px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  background-color: white;
  padding: 10px;
  width: 300px;

  .bee-ele-row {
    display: flex;

    .bee-ele-saturation {
      width: 280px;
      height: 180px;
    }

    .bee-ele-hue {
      margin-left: 10px;
      height: 180px;
    }
  }
}
</style>
